#include "stl-helper.h"

vi_t RAND::randperm(int n)
{
  vi_t perm(n);
  for (int i = 0; i < n; i++)
    perm[i] = i;
  for (int i = 0; i < n; i++) {
    int r = rand() % (n-i);
    std::swap(perm[i], perm[r+i]);
  }
  return perm;
}

void FileAccess::open2read(std::ifstream& input, const std::string& fName)
{
  input.open(fName.c_str());
  if (!input.good())
    FATAL_ERROR("cannot open " << fName << " to read.");
}

void FileAccess::open2write(std::ofstream& output, const std::string& fName)
{
  output.open(fName.c_str());
  if (!output.good())
    FATAL_ERROR("cannot open " << fName << " to write.");
}

void FileAccess::open2append(std::ofstream& output, const std::string& fName)
{
  output.open(fName.c_str(), std::ios::app);
  if (!output.good())
    FATAL_ERROR("cannot open " << fName << " to append.");
}

void FileAccess::append_row(std::ostream& output, const arma::vec& v)
{
  for (int i = 0; i < sz(v); i++)
    output << v[i] << "\t ";
  output << ENDL;
}

std::string FileAccess::getline(std::ifstream& input) {
  std::string line;
  std::getline(input, line);
  return line;
}

void FileAccess::readrows(std::ifstream& input, vvd_t& s) {
  while (!input.eof()) {
    std::string line;
    std::vector<std::string> tokens;
    std::vector<double> d_tmp;
    //vd_t d;

    std::getline(input, line);
    boost::split(tokens, line, boost::is_any_of("\t \n"), boost::token_compress_on);

    BOOST_FOREACH(const std::string& tk, tokens) {
      if (tk == "") continue;
      d_tmp.pb(RAND::s2type<double>(tk));
    }
    if (sz(d_tmp) == 0) continue;
      
    vd_t d(sz(d_tmp));
    for (int i = 0; i < sz(d_tmp); i++) d[i] = d_tmp[i];
    s.pb(d);
  }
}


double LogNumber::add(double a, double b) {
  if (a == -std::numeric_limits<double>::infinity()) return b;
  if (b == -std::numeric_limits<double>::infinity()) return a;
  if (b > a) std::swap(a, b);
  return a + boost::math::log1p(exp(b-a));
}

double LogNumber::div(double a, double b) {
  return a - b;
}

double LogNumber::mul(double a, double b) {
  return a + b;
}

double LogNumber::zero() {
  return log(0.0);
}

double LogNumber::one() {
  return log(1.0);
}

double LogNumber::randu(double s) {
  return log(arma::randu()) + s;
}

double LogNumber::sum(const arma::vec& v) {
  double s = zero();
  BOOST_FOREACH(double x, v) {
    s = add(s, x);
  }
  return s;
}

void LogNumber::normalize(arma::vec& v) {
  double s = sum(v);
  BOOST_FOREACH(double& x, v) {
    x = div(x, s);
  }
}

